﻿using System;
using System.Diagnostics;
using System.Linq;
using Reflector.CodeModel;

namespace CallGraphExtractor.CecilAdapter
{
    [DebuggerDisplay("{Name}")]
    abstract class MemberDeclaration : IMemberReference, IMemberDeclaration
    {
        #region Lifecycle

        protected MemberDeclaration(Mono.Cecil.MemberReference memberReference)
        {
            this.Adaptee = memberReference;
#if DEBUG
            if (this.Adaptee == null)
                ;
#endif
        }

        #endregion Lifecycle

        #region Properties

        protected Mono.Cecil.MemberReference Adaptee { get; private set; }

        #endregion Properties

        #region Methods

        public override string ToString()
        {
            string[] tokens = this.Adaptee.FullName.Split(' ');
            tokens[0] = "";
            string s = string.Concat(tokens);//.;
            if (this.Adaptee.DeclaringType.IsNested == false)
            {
                string[] typeNameAndMemberName =
                    s.Split(new string[] { "::" }, StringSplitOptions.RemoveEmptyEntries);
                if (typeNameAndMemberName.Length == 2)
                    s = typeNameAndMemberName[0].Replace(this.Adaptee.DeclaringType.Namespace + ".", "")
                        + "::" + typeNameAndMemberName[1];
                else if (typeNameAndMemberName.Length == 1)
                    ;
#if DEBUG
                else
                    ;//It must be impossible to reach
#endif
            }
            else
            {
                string fn = this.Adaptee.DeclaringType.FullName;
                string n = this.Adaptee.DeclaringType.Name;
                string toRemove = fn.Replace(n, "");
                s = s.Replace(toRemove, "");
            }
            #region Case of explicit interface implementation
            string[] typeNameAndMemberName2 = s.Split(new string[] { "::" }, StringSplitOptions.RemoveEmptyEntries);
            string[] memberName =
                typeNameAndMemberName2.Last().Split(new char[] { '(' }, StringSplitOptions.RemoveEmptyEntries);
            string memberN = memberName.First();
            bool l = false;
            foreach (var interf in this.Adaptee.DeclaringType.Resolve().Interfaces)
            {
                if (memberN.Contains(interf.FullName) == true)
                {
                    l = true;
                    break;
                }
            }
            if (l == true)
                return s.Split(new string[] { "::" }, StringSplitOptions.RemoveEmptyEntries).Last().Replace('/', '.');
            #endregion Case of explicit interface implementation
            else
                return s.Replace("::", ".").Replace('/', '.');
        }

        #endregion Methods

        #region IMemberReference Members

        public IType DeclaringType
        {
            get
            {
                Mono.Cecil.TypeDefinition td = this.Adaptee.DeclaringType.Resolve();
                if (td == null)
                    throw new NotSupportedException("Resolve() on " + this.Adaptee.DeclaringType.FullName + " is not supported!");
                return new TypeDeclaration(td);
            }
            set { throw new NotSupportedException(); }
        }

        public string Name
        {
            get { return this.Adaptee.Name; }
            set { throw new NotSupportedException(); }
        }

        #endregion

        #region IComparable Members

        public int CompareTo(object obj)
        {
            throw new NotImplementedException();
        }

        #endregion

        #region ICustomAttributeProvider Members

        public ICustomAttributeCollection Attributes
        {
            get { throw new NotImplementedException(); }
        }

        #endregion

        #region IDocumentationProvider Members

        public string Documentation
        {
            get
            {
                throw new NotImplementedException();
            }
            set
            {
                throw new NotImplementedException();
            }
        }

        #endregion
    }
}
